/**
 * @(#)AbstractActionHandler.java 
 *
 * $Id:AbstractActionHandler.java 1 2014/09/20 22:48 jiuping_yi $
 *
 * Real time Convergent Charging and Policy Platform
 *
 * Copyright (C) 2009-2013 Hewlett-Packard Company
 */
package com.hp.snap.gr.action.impl;

import com.hp.snap.gr.action.ActionHandler;
import com.hp.snap.gr.exception.ActionException;
import com.hp.snap.gr.model.jaxb.*;
import com.hp.snap.gr.utils.ExpressionHelper;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * <p>AbstractActionHandler</p>
 *
 * @author Joey Yi
 */
public abstract class AbstractActionHandler implements ActionHandler {
    private static Logger logger = LoggerFactory.getLogger(AbstractActionHandler.class);

    @Override
    public void preProcess(ActionType action, Map<String, Object> context) throws ActionException {
        if (logger.isTraceEnabled()) {
            logger.trace("Start to pre-process the action definition: {}", action.getName());
        }

        try {
            convertExpressionInActionParameters(action, context);
            if (action instanceof GeneralActionType) {
                GeneralActionType generalAction = (GeneralActionType) action;

                List<ParameterType> parameterTypes = generalAction.getParameter();
                if (parameterTypes != null && !parameterTypes.isEmpty()) {
                    for (ParameterType parameterType : parameterTypes) {
                        String originalValue = !StringUtils.isEmpty(parameterType.getVal()) ? parameterType.getVal()
                                : parameterType.getValue();
                        String value = ExpressionHelper.executeTemplate(context, originalValue);
                        parameterType.setVal(value);
                        parameterType.setValue(value);
                    }
                }

            } else if (action instanceof RemoteShellActionType) {
                RemoteShellActionType remoteShellAction = (RemoteShellActionType) action;

                if (remoteShellAction.isIsFile()) {
                    File shellFile = new File(remoteShellAction.getShell());
                    String shellContent = ExpressionHelper.executeTemplate(context, shellFile);

                    remoteShellAction.setShell(shellContent);
                }
            } else if (action instanceof LocalShellActionType) {
                LocalShellActionType actionType = (LocalShellActionType) action;
                if (actionType.isIsFile()) {
                    String shellContent = ExpressionHelper.executeTemplate(context, actionType.getShell());

                    actionType.setShell(shellContent);
                }
            } else if (action instanceof RESTfulInvokeActionType) {
                RESTfulInvokeActionType restfulInvokeAction = (RESTfulInvokeActionType) action;

                List<RESTfulParameterType> parameterTypes = restfulInvokeAction.getParameter();
                if (parameterTypes != null && !parameterTypes.isEmpty()) {
                    for (RESTfulParameterType parameterType : parameterTypes) {
                        String originalValue = !StringUtils.isEmpty(parameterType.getVal()) ? parameterType.getVal()
                                : parameterType.getValue();
                        String value = ExpressionHelper.executeTemplate(context, originalValue);
                        parameterType.setVal(value);
                        parameterType.setValue(value);
                    }
                }
            } else if (action instanceof FileReplaceActionType) {
                FileReplaceActionType actionType = (FileReplaceActionType) action;

                List<ReplaceType> replaces = actionType.getReplace();
                for (ReplaceType r : replaces) {
                    if (StringUtils.isNotEmpty(r.getFrom())) {
                        r.setFrom(ExpressionHelper.executeTemplate(context, r.getFrom()));
                    }
                    if (StringUtils.isNotEmpty(r.getTo())) {
                        r.setTo(ExpressionHelper.executeTemplate(context, r.getTo()));
                    }
                }
            }

        } catch (Exception e) {
            throw new ActionException("Pre-process action failed: " + action.getName(), e);
        }

        if (logger.isTraceEnabled()) {
            logger.trace("Finished to pre-process the action definition: {}", action.getName());
        }

    }

    private void convertExpressionInActionParameters(ActionType action, Map<String, Object> context) throws ActionException {
        for (Method getMethod : action.getClass().getMethods()) {
            if (getMethod.getName().startsWith("get") && getMethod.getReturnType() == String.class) {
                String beanName = getMethod.getName().substring(3);
                Method setMethod = null;
                try {
                    setMethod = action.getClass().getMethod("set" + beanName, getMethod.getReturnType());
                } catch (NoSuchMethodException e) {
                    //method is not a bean properties
                }
                if (setMethod != null) {
                    try {
                        String value = (String) getMethod.invoke(action);

                        if (StringUtils.isNotEmpty(value)) {
                            setMethod.invoke(action, ExpressionHelper.executeTemplate(context, value));
                        }
                    } catch (IllegalAccessException e) {
                        logger.warn("invoke method {} failed, reason: {}", getMethod.getName(), e.getMessage());
                    } catch (InvocationTargetException e) {
                        logger.warn("invoke method {} failed, reason: {}", getMethod.getName(), e.getMessage());
                    }
                }
            }
        }
    }
}
